//
//  FMacroDefine.h
//  FFoundation
//
//  Created by 三井 on 2019/11/1.
//

#ifndef FMacroDefine_h
#define FMacroDefine_h

#import <objc/message.h>

#define F_macro_concat_(A, B) A ## B

#define F_macro_concat(A, B) \
    F_macro_concat_(A, B)

#define F_macro_head_(First, ...) First
#define F_macro_head(...)\
    F_macro_head_(__VA_ARGS__, 0)

#define F_macro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) \
    F_macro_head(__VA_ARGS__)

#define F_macro_at(N, ...) \
    F_macro_concat(F_macro_at, 20)(__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

#define F_macro_argcount(...) \
    F_macro_at(20, __VA_ARGS__)


#pragma mark - objc_msgSend Max Arg is 6
#define F_macro_msgSend_type_arg0(_rt_) \
    (_rt_ (*)(id, SEL))
#define F_macro_msgSend_type_arg1(_rt_) \
    (_rt_ (*)(id, SEL, id))
#define F_macro_msgSend_type_arg2(_rt_) \
    (_rt_ (*)(id, SEL, id, id))
#define F_macro_msgSend_type_arg3(_rt_) \
    (_rt_ (*)(id, SEL, id, id, id))
#define F_macro_msgSend_type_arg4(_rt_) \
    (_rt_ (*)(id, SEL, id, id, id, id))
#define F_macro_msgSend_type_arg5(_rt_) \
    (_rt_ (*)(id, SEL, id, id, id, id, id))
#define F_macro_msgSend_type_arg6(_rt_) \
    (_rt_ (*)(id, SEL, id, id, id, id, id, id))

#define F_macro_msgSend_type_(_type_) \
    _type_

#define F_macro_msgSend_type(_rt_, ...) \
    F_macro_msgSend_type_( F_macro_concat(F_macro_msgSend_type_arg, F_macro_argcount(__VA_ARGS__))(_rt_) )

#define F_macro_msgSend_func(_rt_, ...) \
    (F_macro_msgSend_type(_rt_, __VA_ARGS__) objc_msgSend)

#define F_macro_msgSend(_rt_, _target_, _sel_, ...) \
    F_macro_msgSend_func(_rt_, __VA_ARGS__)(_target_, _sel_, __VA_ARGS__)
    
#define F_macro_delegate_result __F_macro_delegate_return_arg_

#define F_macro_delegate(_rt_, _target_, _sel_, ...) \
if ([_target_ respondsToSelector:_sel_]) {\
    F_macro_msgSend(_rt_, _target_, _sel_, __VA_ARGS__);\
}

#define F_macro_delegate_return(_rt_, _target_, _sel_, ...) \
_rt_ F_macro_delegate_result = nil;\
if ([_target_ respondsToSelector:_sel_]) {\
    F_macro_delegate_result = F_macro_msgSend(_rt_, _target_, _sel_, __VA_ARGS__);\
}

#pragma mark - Category Property
#define F_macro_property_key( _prop_ ) _prop_ ## Key
#define F_macro_property( _prop_ ) static const void * F_macro_property_key(_prop_) = &F_macro_property_key(_prop_);
#define F_macro_property_imp( _prop_, _type_ )\
- (id)_prop_ {\
    return objc_getAssociatedObject(self, F_macro_property_key(_prop_));\
}\
- (void)set ## _prop_:(id)_prop_ {\
    objc_setAssociatedObject(self, F_macro_property_key(_prop_), _prop_, _type_);\
}
#endif /* FMacroDefine_h */


//解循环引用
#ifndef weakify
#if DEBUG
#if __has_feature(objc_arc)
#define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
#else
#define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
#endif
#else
#if __has_feature(objc_arc)
#define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
#else
#define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
#endif
#endif
#endif

#ifndef strongify
#if DEBUG
#if __has_feature(objc_arc)
#define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
#else
#define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
#endif
#else
#if __has_feature(objc_arc)
#define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
#else
#define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
#endif
#endif
#endif
